#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>

using namespace std;

const int IP_HEADER_LEN = 20;
const int OFFSET_UNIT = 8;

struct Fragment {
    int totalLength;
    int offset;
    bool moreFragments;
};

vector<Fragment> fragmentPacket(int packetLength, const vector<int>& pathMTUs) {
    vector<Fragment> resultFragments;

    int originalDataLength = packetLength - IP_HEADER_LEN;
    if (originalDataLength <= 0) {
        if (packetLength > 0) {
            resultFragments.push_back({packetLength, 0, false});
        }
        return resultFragments;
    }

    int minUsableDataLength = 65536;

    for (int mtu : pathMTUs) {
        if (mtu <= IP_HEADER_LEN) {
            cerr << "Warning: MTU (" << mtu << "B) <= Header Length (20B). Cannot transmit." << endl;
            continue; 
        }

        int maxDataLength = mtu - IP_HEADER_LEN; 
        
        int usableDataLength = (maxDataLength / OFFSET_UNIT) * OFFSET_UNIT; 
        
        minUsableDataLength = min(minUsableDataLength, usableDataLength);
    }
    
    if (minUsableDataLength <= 0) {
        cerr << "Error: No valid path MTU found or min usable data length is zero." << endl;
        return {};
    }
    
    if (originalDataLength <= minUsableDataLength) {
        resultFragments.push_back({packetLength, 0, false});
        return resultFragments;
    }

    int currentOffsetBytes = 0;
    int remainingData = originalDataLength;
    
    int totalFragments = (originalDataLength + minUsableDataLength - 1) / minUsableDataLength;
    int currentFragmentIndex = 0;

    while (remainingData > 0) {
        currentFragmentIndex++;
        
        int currentDataLength;
        bool moreFragments;

        if (currentFragmentIndex < totalFragments) {
            currentDataLength = minUsableDataLength;
            moreFragments = true; 
        } else {
            currentDataLength = remainingData;
            moreFragments = false;
        }

        Fragment f;
        f.totalLength = currentDataLength + IP_HEADER_LEN;
        f.offset = currentOffsetBytes / OFFSET_UNIT;
        f.moreFragments = moreFragments;

        resultFragments.push_back(f);

        remainingData -= currentDataLength;
        currentOffsetBytes += currentDataLength;
    }

    return resultFragments;
}

void printFragments(const vector<Fragment>& fragments) {
    if (fragments.empty()) {
        cout << "无法传输或分片列表为空。" << endl;
        return;
    }
    
    cout << "总分片数: " << fragments.size() << endl;
    cout << "最小可用数据长度 (MA_min): " << (fragments.size() > 1 ? fragments[0].totalLength - IP_HEADER_LEN : 0) << " B" << endl;
    cout << "--- 分片详情 ---" << endl;
    cout << left << setw(10) << "序号"
         << setw(15) << "报文总长(B)" 
         << setw(15) << "数据长度(B)"
         << setw(15) << "偏移量(8B)" 
         << "更多分片(MF)" << endl;
    
    for (size_t i = 0; i < fragments.size(); ++i) {
        cout << left << setw(10) << i + 1
             << setw(15) << fragments[i].totalLength
             << setw(15) << fragments[i].totalLength - IP_HEADER_LEN
             << setw(15) << fragments[i].offset
             << (fragments[i].moreFragments ? "Yes" : "No") << endl;
    }
}

int main() {
    int packetLength = 24 * 1024; 
    
    vector<int> pathMTUs = {4325, 2346, 1500, 4464, 2346};

    cout << "--- 原始报文信息 (24KB) ---" << endl;
    cout << "报文总长: " << packetLength << " B" << endl;
    cout << "数据长度: " << packetLength - IP_HEADER_LEN << " B" << endl;
    cout << "IP 报头长度: " << IP_HEADER_LEN << " B" << endl;
    cout << "MTU 路径: [";
    for(size_t i = 0; i < pathMTUs.size(); ++i) {
        cout << pathMTUs[i] << (i < pathMTUs.size() - 1 ? ", " : "");
    }
    cout << "]" << endl;
    cout << "----------------------------------" << endl;

    vector<Fragment> fragments = fragmentPacket(packetLength, pathMTUs);
    printFragments(fragments);
    
    cout << "\n====================================" << endl;

    cout << "--- 测试案例 3：MTU 严格限制 (5020B 报文, 1500B MTU) ---" << endl;
    vector<int> pathMTUs_strict = {1500, 1500, 1500};
    int largePacket = 5020; 
    
    cout << "报文总长: " << largePacket << " B" << endl;
    cout << "MTU 路径: [1500, 1500, 1500]" << endl;
    cout << "----------------------------------" << endl;

    fragments = fragmentPacket(largePacket, pathMTUs_strict);
    printFragments(fragments);

    return 0;
}
